//MyTax: a simple software for U.S. Federal Personal Income Tax.
//Copyright (C) 2009-2010 MyTax Team.
//Contact: mytax_have@yahoo.com
//
//This library is free software; you can redistribute it and/or
//modify it under the terms of the GNU Lesser General Public
//License as published by the Free Software Foundation; either
//version 2.1 of the License, or (at your option) any later version.
//
//This library is distributed in the hope that it will be useful,
//but WITHOUT ANY WARRANTY; without even the implied warranty of
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//Lesser General Public License for more details.
//
//You should have received a copy of the GNU Lesser General Public
//License along with this library; if not, write to the Free Software
//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//

#include "math.h"
#include "map"
#include "fstream"
#include "iostream"
#include "string"

using namespace std;

#define rag_cnt 6

enum FILL_STATUS
{
	SINGLE, MARRIED_JOINTLY, MARRIED_SEPARATELY, HEAD_HOUSEHELD
};

class Form1040
{
protected:
	float wage_w2;
	float taxable_interest;
	float total_income;
	float adj_gro_income;
	float taxable_income;
	float tax, total_tax;
	float tax_from_table;
	float deduction;
	float exemption_total;
	float federal_withheld;
	float total_credit;
	float total_payment;
	float state_income_tax;
	float overpaid;
	float paid_extension;	//when you file extension, you need pay tax first.
	int tax_year;
	string tax_year_str;
	string form_name;
	FILL_STATUS filling_status;
	int kid_num;
	map <int, float> tax_table;
	int deduction_num;
	int form_1099_num;
	string visa_status;
	string citizenship;
	float stand_deduct;
/// not used in table
	float exemption;
	float deduct_single;		// maybe moved to Form1040_R
	float deduct_jointly;
	float deduct_separately;
	float deduct_head;
	float child_tax_credit;
	bool first_time_home_buyer;
	float mortgage_interest;
	float points_on_purchase;
	float overpaid_interest;
	float real_estate_taxes;
	float mortgage_insurance;
	float range[rag_cnt], rag_rate[rag_cnt];
	string path;
public:
	void Init( string );	
	void InitTaxRate( void );	
	void ReadFormW2( void );
	void ReadForm1099INT( void );
	void ReadForm1098( void );
	void ReadInputs( void );
	void ReadTaxTable( string name );
	float FindTax( void );
	void ScheduleA( void );
	void Run( void );
	void PrintForm( void );
};

void Form1040::Init( string input_path )
{	
	// initilize variables
	total_payment = 0.0; 
	paid_extension = 0.0;
	path = "./";
	path += input_path;

	// read inputs;
	ReadInputs();
	switch (tax_year)
	{
	case 2006:
		exemption			= 3300.; // year 2006 1040 exemption
		deduct_single		= 5150.;
		deduct_jointly		= 10300.;
		deduct_separately	= 5300.;
		deduct_head			= 7550.;
		child_tax_credit	= 1000.;
		break;
	case 2007:
		exemption			= 3400.; // year 2007 1040 exemption
		deduct_single		= 5300.;
		deduct_jointly		= 10700.;
		deduct_separately	= 5300.;
		deduct_head			= 7850.;
		child_tax_credit	= 1000.;
		break;
	case 2008:
		exemption			= 3500.; // year 2008 1040 exemption
		deduct_single		= 5450.;
		deduct_jointly		= 10900.;
		deduct_separately	= 5450.;
		deduct_head			= 8000.;
		child_tax_credit	= 1000.;
		break;
	case 2009:
		exemption			= 3650.; // year 2009 1040 exemption
		deduct_single		= 5700.;
		deduct_jointly		= 11400.;
		deduct_separately	= 5700.;
		deduct_head			= 8350.;
		child_tax_credit	= 1000.;
		break;
	}
	InitTaxRate();
	// read W2 form
	ReadFormW2();
	ReadForm1099INT();
	ReadForm1098();

	// read tax table, create tax table name form file
	string tax_table_name = "./TaxTable/";
	tax_table_name += tax_year_str;

	switch ( filling_status )
	{
	case SINGLE:
		tax_table_name += "_single.txt";
		stand_deduct = deduct_single;
		break;
	case MARRIED_SEPARATELY:
		tax_table_name += "_separately.txt";
		stand_deduct = deduct_separately;
		break;
	case MARRIED_JOINTLY:
		tax_table_name += "_jointly.txt";
		stand_deduct = deduct_jointly;
		break;
	case HEAD_HOUSEHELD:
		tax_table_name += "_househeld.txt";
		stand_deduct = deduct_head;
		break;
	}

	ReadTaxTable( tax_table_name );
}
void Form1040::InitTaxRate( void )
{
	rag_rate[0] = 0.1f;
	rag_rate[1] = 0.15f;
	rag_rate[2] = 0.25f;
	rag_rate[3] = 0.28f;
	rag_rate[4] = 0.33f;
	rag_rate[5] = 0.35f;

	switch( tax_year )
	{
	case 2008:
		switch ( filling_status )
		{
		case SINGLE:
			range[0] = 0.0;
			range[1] = 8025.;
			range[2] = 32550.;
			range[3] = 78850.;
			range[4] = 164550.;
			range[5] = 357700.;
			break;
		case MARRIED_SEPARATELY:
			range[0] = 0.0;
			range[1] = 8025;
			range[2] = 32500.;
			range[3] = 65725.;
			range[4] = 100150.;
			range[5] = 178850.;
			break;
		case MARRIED_JOINTLY:
			range[0] = 0.0;
			range[1] = 16050.;
			range[2] = 65100.;
			range[3] = 131450.;
			range[4] = 200300.;
			range[5] = 357700.;
			break;
		case HEAD_HOUSEHELD:
			range[0] = 0.0;
			range[1] = 11450.;
			range[2] = 43650.;
			range[3] = 112650.;
			range[4] = 182400.;
			range[5] = 357700.;
			break;
		}
	}
}
void Form1040::ReadFormW2( void )
{
	wage_w2				= 0.0;
	federal_withheld	= 0.0;
	state_income_tax	= 0.0;

	int n;
	string item;
	float value;
	string file_name;
	file_name = path + "/w2.txt";
	fstream file_op( file_name.c_str(), ios::in );
	int count = 0;
	if (file_op.is_open() == true )
	{
		cout << "Reading Form W2 ...\t"; 
		while(!file_op.eof()) 
		{
			file_op >> n;
			file_op >> item;
			file_op >> value;
			count ++;
			if (item == "Wages_tips_other_compensation")
				wage_w2 = wage_w2 + value;
			else if(item == "Federal_income_tax_withheld")
				federal_withheld = federal_withheld + value;
			else if(item == "State_income_tax")
				state_income_tax = state_income_tax + value;
		}
		cout << " done. Total got " << count << " records." << endl;
	}
	file_op.close();
}

void Form1040::ReadForm1099INT( void )
{
	taxable_interest = 0.0;
	string item;
	int n;
	float value;
	string file_name;
	file_name = path + "/Form_1099INT.txt";
	fstream file_op( file_name.c_str(), ios::in );
	int count = 0;
	if (file_op.is_open() == true )
	{
		cout << "Reading Form 1099INT ..."; 
		while(!file_op.eof()) 
		{
			file_op >> n;
			file_op >> item;
			file_op >> value;
			count ++;
			if (item == "Interest_income")
				taxable_interest += value;
		}
		cout << " done. Total got " << count << " records." << endl;
	}
	file_op.close();

}
void Form1040::ReadForm1098( void )
{
	fstream file_op;
	mortgage_interest = 0.0;
	points_on_purchase = 0.0;
	overpaid_interest = 0.0;
	real_estate_taxes = 0.0;
	mortgage_insurance = 0.0;
	int n;
	string item;
	float value;
	string file_name;
	file_name = path + "/Form_1098.txt";
	int count = 0;
	file_op.open( file_name.c_str(),ios::in );
	if (file_op.is_open() == true )
	{
		cout << "Reading Form 1098 ...\t"; 
		while(!file_op.eof()) 
		{
			file_op >> n;
			file_op >> item >> value;
			count ++;
			if (item == "Mortage_interest_received")
				mortgage_interest += value;
			if (item == "Points_paid_on_purchase")
				points_on_purchase += value;
			if (item == "Refund_of_overpaid_interest")
				overpaid_interest += value;
			if (item == "Mortgage_insurance_preminums")
				mortgage_insurance += value;
			if (item == "Real_estate_taxes")
				real_estate_taxes += value;
		}
		cout << " done. Total got " << count << " records." << endl;
	}
	file_op.close();

}
void Form1040::ReadInputs( void )
{
	string item;
	string value;
	string file_name;
	file_name = path + "/inputs.txt";
	fstream file_op( file_name.c_str(),ios::in );
	int count = 0;
	if (file_op.is_open() == true )
	{
		cout << "Reading input file ...\t"; 
		while(!file_op.eof()) 
		{
			file_op >> item;
			file_op >> value;
			count ++;
			if (item == "Year")
			{
				 tax_year = atoi( value.c_str() ); 
				 tax_year_str = value;
			}
			else if(item == "Form")
				form_name = value;
			else if(item == "Fill_status")
			{
				if(value == "single")
					filling_status = SINGLE;
				else if( value == "married_jointly" )
					filling_status = MARRIED_JOINTLY;
				else if( value == "married_sparately" )
					filling_status = MARRIED_SEPARATELY;
				else if( value == "head_househeld" )
					filling_status = HEAD_HOUSEHELD;
				else
					; //show error message
			}
			else if(item == "1099_form")
				form_1099_num = atoi( value.c_str() );
			else if(item == "Child")
				kid_num = atoi( value.c_str() );
			else if(item == "Deductions")
				deduction_num = atoi( value.c_str() );
			else if(item == "Visa")
				visa_status = value;
			else if(item == "Citizenship")
				citizenship = value;
			else if(item == "Paid_extension")
				paid_extension = ( float ) atof( value.c_str() );
			else if(item == "Firt_year_home_buyer")
			{
				if( value == "yes")
					this->first_time_home_buyer = true;
				else	  first_time_home_buyer = false;
			}
		}
		cout << " done. Total got " << count << " records." << endl;
	}
	file_op.close();
}
void Form1040::ReadTaxTable( string name )
{
	int v1;
	float v2;
	fstream file_op;
	file_op.open( name.c_str(), ios::in );
	if (file_op.is_open() == true )
	{
		while(!file_op.eof()) 
		{
			file_op >> v1;
			file_op >> v2;
			tax_table[ v1 ] = v2;
		}
	}
	file_op.close();
}
float Form1040::FindTax( void )
{
	float calc;
	// format taxable income to be tax table style
	if( fabs( (int)(taxable_income / 50.) * 50 - taxable_income ) < 0.001 )
	{
		calc = taxable_income - 25.0;
	}
	else
	{
		float upper = ceil ( ( taxable_income / 50) ) * 50;
		float lower = floor( ( taxable_income / 50) ) * 50;
		calc = ( upper + lower ) / 2.0;
	}

	int pos;
	for( int i = rag_cnt - 1; i >= 0; i -- )
	{
		if( calc > range[i] )
		{
			pos = i;
			break;
		}
	}
	float v1 = calc;
	float sum = 0.0;
	for( int i = pos; i >= 0; i --)
	{
		sum = sum + ( v1 - range[i] ) * rag_rate[i];
	    v1 = range[i];
	}

	// round to integer value
	if( ( sum - (int) sum ) > 0.5 )
		return ceil( sum );
	else
		return floor( sum );
}
void Form1040::ScheduleA( void )
{
	float itemized_deduct = state_income_tax + real_estate_taxes;
	itemized_deduct += mortgage_interest;
	itemized_deduct += mortgage_insurance;
	if ( adj_gro_income > 159950)	// according to year
	{
		// to do: 

	}
	
	if ( itemized_deduct <= stand_deduct )	
		deduction = stand_deduct;
	else	
		deduction = itemized_deduct;
}
void Form1040::Run( void )
{
	total_income = wage_w2 + taxable_interest;
	if (visa_status == "F1-H1B" || visa_status == "F1")
	{
		if (citizenship == "China")
		{
			 total_income -= 5000;
		}
	}

	adj_gro_income = total_income;

	ScheduleA();	// for deduction

	if (tax_year == 2008 && first_time_home_buyer) deduction += 1000.0;  // only for 2008 and 2009
	
	exemption_total = deduction_num * exemption;
	taxable_income = adj_gro_income - deduction - exemption_total;
	tax_from_table = FindTax();

	child_tax_credit = child_tax_credit * kid_num;		//child tax credit

	total_credit = child_tax_credit;

	tax = tax_from_table - total_credit;
	
	total_payment += federal_withheld;
	if (tax_year == 2008 && first_time_home_buyer)	total_payment += 7500.0; // only for 2008 and 2009
	if (paid_extension > 0.0)	total_payment += paid_extension;
    overpaid = total_payment - tax;
}


void Form1040::PrintForm( void )
{
	cout << "Generating Form " << form_name << " ...";
	string form_name;
	form_name = path + "/" + tax_year_str + "_Form1040.txt";
	fstream file_op( form_name.c_str(), ios::out );
	file_op << " 7 Wages, salaries, tips, etc. Attach Form(s) W2...\t\t\t\t\t\t\t\t" << wage_w2 << "\n";
	file_op << "8a Taxable interest. Attach Schedual B if required...\t\t\t\t\t\t\t" << taxable_interest << "\n";
	if (visa_status == "F1-H1B" || visa_status == "F1")
	{
		if (citizenship == "China")
		{
			 file_op << "21 Other income. List type and amout (see page 28)...\t\t\t\t\t\t\t" << -5000 << "\n";
		}
	}
	file_op << "22 Add the amounts in the far right column for lines 7 through 21...\t\t\t" << total_income << "\n";
	file_op << "37 Subtract line 36 from line 22. This is your adjusted gross income....\t\t" << adj_gro_income << "\n";
	file_op << "38 Amount from line 37 (adjusted gross income)....\t\t\t\t\t\t\t\t" << adj_gro_income << "\n";
	file_op << "40 Itemized deductions (from Schedule A) or your standard deduction...\t\t\t" << deduction << "\n";
	file_op << "41 Subtract line 40 from line 38...\t\t\t\t\t\t\t\t\t\t\t\t" << adj_gro_income - deduction << "\n";

	switch ( tax_year )
	{
	case 2006:
		file_op << "42 If line 38 is over $112,875, or you provided housing to a person displaced by Hurricane Katrina," << "\n";
		file_op << "   see page 36.  Otherwise, multiply $3,300 by the total number of exemptions claimed on line 6d...." << exemption_total << "\n";
		break;
	case 2007:
		file_op << "42 If line 38 is $117,300 or less, multiply $3,400 by the total number of exemptions claimed on line" << "\n";
		file_op << "   6d. If line 38 is over $117,300, see the worksheet on page 33....\t\t\t" << exemption_total << "\n";
		break;
	case 2008:
		file_op << "42 If line 38 is over $119,975 or you provided housing to a Midwestern displaced individual, see" << "\n";
		file_op << "   page 36.  Otherwise, multiply $3,500, by the total number of exemptions claimed on line 6d...." << exemption_total << "\n";
		break;
	case 2009:
		file_op << "42 Exemptions. If line 38 is $125,100 or less and you did not provide housing to a Midwestern" << "\n";
		file_op << "   displaced individual, multiply $3,650 by the number on line 6d. Otherwise, see page 37...." << exemption_total << "\n";
		break;
	}
	
	file_op << "43 Taxable income. Subtract line 42 from line 41....\t\t\t\t\t\t\t" << taxable_income << "\n";
	file_op << "44 Tax (see pg 36) Check if any tax is from:a...\t\t\t\t\t\t\t\t" << tax_from_table << "\n";
	file_op << "46 Add lines 44 and 45...\t\t\t\t\t\t\t\t\t\t\t\t\t\t" << tax_from_table << "\n";
	
	switch ( tax_year )
	{
	case 2006:
		file_op << "53 Child tax credit (see page 42). Attach Form 8901 if required...\t\t\t\t" << child_tax_credit << "\n";
		file_op << "57 Add lines 47 through 55. These are your total credits...\t\t\t\t\t\t" << total_credit << "\n";
		file_op << "57 Subtract line 56 from line 46. If line 56 is more than line 46, enter 0...\t" << tax << "\n";
		file_op << "63 Add lines 57 through 62. This is your total tax...\t\t\t\t\t\t\t" << tax << "\n";
		file_op << "64 Federal income tax withheld from Forms W-2 and 1099...\t\t\t\t\t\t" << federal_withheld << "\n";
		file_op << "72 Add lines 64, 65, 66a, and 67 through 71....\t\t\t\t\t\t\t\t\t" << total_payment << "\n";
		file_op << "73 If line 72 is more than line 63, subtract line 63 from line 72. This is the amount you overpaid. " << overpaid << "\n";
		break;
	case 2007:
		file_op << "52 Child tax credit (see page 42). Attach Form 8901 if required...\t\t\t\t" << child_tax_credit << "\n";
		file_op << "56 Add lines 47 through 55. These are your total credits...\t\t\t\t\t\t" << total_credit << "\n";
		file_op << "57 Subtract line 56 from line 46. If line 56 is more than line 46, enter 0...\t" << tax << "\n";
		file_op << "63 Add lines 57 through 62. This is your total tax...\t\t\t\t\t\t\t" << tax << "\n";
		file_op << "64 Federal income tax withheld from Forms W-2 and 1099...\t\t\t\t\t\t" << federal_withheld << "\n";
		file_op << "72 Add lines 64, 65, 66a, and 67 through 71....\t\t\t\t\t\t\t\t\t" << total_payment << "\n";
		file_op << "73 If line 72 is more than line 63, subtract line 63 from line 72. This is the amount you overpaid. " << overpaid << "\n";
		break;
	case 2008:
		file_op << "52 Child tax credit (see page 42). Attach Form 8901 if required...\t\t\t\t" << child_tax_credit << "\n";
		file_op << "55 Add lines 47 through 54. These are your total credits...\t\t\t\t\t\t" << total_credit << "\n";
		file_op << "56 Subtract line 55 from line 46. If line 55 is more than line 46, enter 0...\t" << tax << "\n";
		file_op << "61 Add lines 56 through 60. This is your total tax...\t\t\t\t\t\t\t" << tax << "\n";
		file_op << "62 Federal income tax withheld from Forms W-2 and 1099...\t\t\t\t\t\t" << federal_withheld << "\n";
		if (first_time_home_buyer)
			file_op << "69 First-time homebuyer credit. Attach Form 5405...\t\t\t\t\t\t\t\t" << 7500 << "\n";
		file_op << "71 Add lines 62 through 70...\t\t\t\t\t\t\t\t\t\t\t\t\t" << total_payment << "\n";
		file_op << "72 If line 71 is more than line 61, subtract line 61 from line 71. This is the amount you overpaid. " << overpaid << "\n";
		break;
	case 2009:
		file_op << "51 Child tax credit (see page 42)...\t\t\t\t\t\t\t\t\t\t\t\t" << child_tax_credit << "\n";
		file_op << "54 Add lines 47 through 53. These are your total credits...\t\t\t\t\t\t" << total_credit << "\n";
		file_op << "55 Subtract line 54 from line 46. If line 54 is more than line 46, enter 0...\t" << tax << "\n";
		file_op << "60 Add lines 55 through 59. This is your total tax...\t\t\t\t\t\t\t" << tax << "\n";
		file_op << "62 Federal income tax withheld from Forms W-2 and 1099...\t\t\t\t\t\t" << federal_withheld << "\n";
		if (first_time_home_buyer)
			file_op << "67 First-time homebuyer credit. Attach Form 5405...\t\t\t\t\t\t\t\t" << 8000 << "\n";
		file_op << "71 Add lines 61, 62, 63, 64a, and 65 through 70. These are your total payments..." << total_payment << "\n";
		file_op << "72 If line 71 is more than line 60, subtract line 60 from line 71. This is the amount you overpaid. " << overpaid << "\n";
		break;

	}
	file_op.close();
	cout << " done." << endl;
}

class Form1040_R : public Form1040  //residence
{
protected:
	Form1040_R( void );
	// not show in the form

public:
};

Form1040_R::Form1040_R( void )
{
	kid_num = 0;
}

class Form1040_NR : public Form1040 //non residence
{};

int main(int argc, char * argv[])
{
	cout << "MyTax 1.0, a simple software for U.S. Federal Personal Income Tax." << endl;
	cout << "Copyright (C) 2009-2010 MyTax Team by LGPL License.\n" << endl;
	if (argc != 2)
	{
		cout << "Usage:   MyTax path_name" << endl;
		cout << "Example: MyTax test" << endl;
	}
	else
	{
		string path = string( argv[1] );
		Form1040 f1040;	
		f1040.Init( path );
		f1040.Run();
		f1040.PrintForm();
		cout << endl;
	}
	return 0;
}